package net.qiqbframework.spring.config;


import lombok.extern.slf4j.Slf4j;
import net.qiqbframework.common.resolving.AnnotatedResolvedAttributes;
import net.qiqbframework.common.utils.AnnotationUtil;
import net.qiqbframework.modelling.command.Cmd;
import net.qiqbframework.modelling.domain.AggregateRoot;
import net.qiqbframework.spring.aggregate.GeneralAggregateConfigurer;
import net.qiqbframework.spring.command.GeneralCommandConfigurer;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;

import java.lang.annotation.Annotation;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;

@Slf4j
public class ManagedConfigurerModuleRegister implements BeanDefinitionRegistryPostProcessor {


    private final Map<Class<? extends Annotation>, Map<String, AbstractBeanDefinition>> managedAnnotationBeanDefinitions = new HashMap<>();

    public void marge(Map<Class<? extends Annotation>, Map<String, AbstractBeanDefinition>> map) {
        if (map == null) {
            return;
        }
        for (Map.Entry<Class<? extends Annotation>, Map<String, AbstractBeanDefinition>> entry : map.entrySet()) {
            managedAnnotationBeanDefinitions.computeIfAbsent(entry.getKey(), k -> entry.getValue());
            for (Map.Entry<String, AbstractBeanDefinition> valueEntry : entry.getValue().entrySet()) {
                if (managedAnnotationBeanDefinitions.get(entry.getKey()).get(valueEntry.getKey()) != null) {
                    if (managedAnnotationBeanDefinitions.get(entry.getKey()).get(valueEntry.getKey()) != valueEntry.getValue()) {
                        throw new IllegalStateException("bean 存在多个不一样的");
                    }
                    continue;
                }
                managedAnnotationBeanDefinitions.get(entry.getKey()).put(valueEntry.getKey(), valueEntry.getValue());
            }

        }
    }


    private ConfigurableListableBeanFactory beanFactory;


    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        this.beanFactory = beanFactory;
    }

    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry bdRegistry) throws BeansException {
        for (Map.Entry<Class<? extends Annotation>, Map<String, AbstractBeanDefinition>> entry : managedAnnotationBeanDefinitions.entrySet()) {
            if (entry.getKey() == Cmd.class) {
                for (Map.Entry<String, AbstractBeanDefinition> beanDefinitionEntry : entry.getValue().entrySet()) {
                    final BeanDefinition beanDefinition = buildCommandBeanDefinition(beanFactory, beanDefinitionEntry.getValue().getBeanClass());

                    bdRegistry.registerBeanDefinition(beanDefinitionEntry.getKey(), beanDefinition);
                }

            }
            if (entry.getKey() == AggregateRoot.class) {
                for (Map.Entry<String, AbstractBeanDefinition> beanDefinitionEntry : entry.getValue().entrySet()) {
                    final BeanDefinition beanDefinition = buildAggregateBeanDefinition(beanFactory, beanDefinitionEntry.getValue().getBeanClass());

                    bdRegistry.registerBeanDefinition(beanDefinitionEntry.getKey(), beanDefinition);
                }

            }

        }

    }

    private BeanDefinition buildCommandBeanDefinition(ConfigurableListableBeanFactory registry,
                                                      Class<?> aggregateType) {

        Optional<Map<String, Object>> annotation = AnnotationUtil.findAnnotationAttributes(aggregateType, Cmd.class);
        if (annotation.isEmpty()) {
            throw new IllegalStateException("命令未指定聚合根对象");
        }
        BeanDefinitionBuilder beanDefinitionBuilder =
                BeanDefinitionBuilder.genericBeanDefinition(GeneralCommandConfigurer.class)
                        .setRole(BeanDefinition.ROLE_APPLICATION)
                        .addConstructorArgValue(aggregateType)
                        .addConstructorArgValue(annotation.get().get("value"));

        return beanDefinitionBuilder.getBeanDefinition();
    }

    private BeanDefinition buildAggregateBeanDefinition(ConfigurableListableBeanFactory registry,
                                                        Class<?> aggregateType) {

        Optional<Map<String, Object>> annotation = AnnotationUtil.findAnnotationAttributes(aggregateType, AggregateRoot.class);
        if (annotation.isEmpty()) {
            throw new IllegalStateException("命令未指定聚合根对象");
        }
        BeanDefinitionBuilder beanDefinitionBuilder =
                BeanDefinitionBuilder.genericBeanDefinition(GeneralAggregateConfigurer.class)
                        .setRole(BeanDefinition.ROLE_APPLICATION)
                        .addConstructorArgValue(aggregateType)
                        .addConstructorArgValue(annotation.get().get("name"));

        return beanDefinitionBuilder.getBeanDefinition();
    }
}
